﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace VDataAdapter
{
    /// <summary>
    /// Concat message old & new and control flag etc
    /// </summary>
    class ProtocolMessageBuilder
    {
        IVdataMessageBuilder _builder;

        DataSource _dataSource;

        public ProtocolMessageBuilder(IVdataMessageBuilder builder, DataSource dataSource){
            
            if (builder != null && dataSource != null)
                throw new NullReferenceException("Cant work with null MessageBuilder & DataSource");
            
            _builder = builder;
            _dataSource = dataSource;
        }

        public string BuildMessageTransactionPutThrough(PriceLibrary.PriceService.StockBase transactionPutThrough)
        {
            throw new NotImplementedException();
        }

        public string BuildMessageMarketInfo(int key, PriceLibrary.PriceService.StockBase marketInfo)
        {
            string msg;
            
            lock (_dataSource.MarketInfos)
            {
                msg = BuildMessageMarketInfo(key, (PriceLibrary.PriceService.MarketInfo)_dataSource.MarketInfos);

                _dataSource.UpdateMarketInfo((PriceLibrary.PriceService.MarketInfo)marketInfo);
            }
            return msg;
        }

        public void UpdateBasePrices(IDictionary<string, PriceLibrary.PriceService.StockBase> basePrices)
        {
            foreach (KeyValuePair<string, PriceLibrary.PriceService.StockBase> p in basePrices)
            {
                var infoStatic =
                    (PriceLibrary.PriceService.StockInfoStatic)p.Value;
                _dataSource.UpdateStockBase(infoStatic);
            }
        }         

        public string BuildMessageStockInfo(string key, PriceLibrary.PriceService.StockInfoDyns dynamicInfo)
        {
            string msg;

            lock(_dataSource.Top3Prices)
            {
                try
                {
                    msg = BuildMessageStockInfo(key, dynamicInfo,
                        (Dictionary<string, PriceLibrary.PriceService.StockInfoDyns>)_dataSource.Top3Prices,
                        (Dictionary<string, PriceLibrary.PriceService.StockInfoStatic>)_dataSource.BasePrices);

                    _dataSource.UpdateStockDynamic(dynamicInfo);
                }
                catch (InvalidCastException ex)
                {
                    throw new InvalidCastException("BuildMessageStockInfo cant convert list of top3prices & baseprices" + ex.Message);
                }
            }

            return msg;
        }
        
        public string BuildMessageTransaction(PriceLibrary.ChartService.Transaction transaction)
        {
            string msg;
            lock (_dataSource.Transactions)
            {                
                // if DataSource already contain this Transaction, send new transaction along with the old
                msg = BuildMessageTransaction(transaction, _dataSource.Transactions);
                // update DataSource anyway
                _dataSource.UpdateTransaction(transaction);
            }
            return msg;
        }

        public string BuildMessagePutThroughTopPrices(string key, PriceLibrary.PriceService.StockInfoDyns stock)
        {
            string msg;
            try
            {
                var objStatic = (PriceLibrary.PriceService.StockInfoStatic)_dataSource.BasePrices[key];

                if (!IsSellPutThrough(stock))
                {
                    var oldStock = (PriceLibrary.PriceService.StockInfoDyns)_dataSource.PtTopPriceBuy[key];
                    msg = _builder.BuildMessagePutThrough(objStatic, stock, oldStock, TransactionType.Buy);
                }
                else
                {
                    var oldStock = (PriceLibrary.PriceService.StockInfoDyns)_dataSource.PtTopPriceSell[key];
                    msg = _builder.BuildMessagePutThrough(objStatic, stock, oldStock, TransactionType.Sell);
                }
            }
            catch (InvalidCastException ex)
            {
                throw new InvalidCastException("Cant convert DataSource: " + ex.Message);
            }

            return msg;
        }

        #region private functions
        private string BuildMessageStockInfo(string key, PriceLibrary.PriceService.StockInfoDyns stockInfo,
           IDictionary<string, PriceLibrary.PriceService.StockInfoDyns> top3Prices,
           IDictionary<string, PriceLibrary.PriceService.StockInfoStatic> basePrices)
        {
            var basePrice = basePrices[key];

            if (top3Prices.ContainsKey(key))
            {
                var stockInfoOld = top3Prices[key];
                return _builder.BuildMessageStock(basePrice, stockInfo, stockInfoOld);
            }
            else
            {
                return _builder.BuildMessageStock(basePrice, stockInfo, stockInfo);
            }
        }
        
        private bool IsSellPutThrough(PriceLibrary.PriceService.StockInfoDyns stock)
        {
            if (stock.Best1BidVolume > 0 && stock.Best1Offer == 0) return false;

            if (stock.Best1Offer > 0 && stock.Best1Offer > 0) return true;

            throw new ArgumentException("Unknown case of StockInfoDyns", "stock");            
        }

        private string BuildMessageMarketInfo(int key, PriceLibrary.PriceService.MarketInfo marketInfo)
        {
            if (!_dataSource.MarketInfos.ContainsKey(key))
                return _builder.BuildMessageMarket(marketInfo, marketInfo);
            else
                return _builder.BuildMessageMarket(marketInfo, (PriceLibrary.PriceService.MarketInfo)_dataSource.MarketInfos[key]);
        }

        private string BuildMessageTransaction(PriceLibrary.ChartService.Transaction transaction, IDictionary<string, PriceLibrary.ChartService.Transaction> transactions)
        {
            string msg;
            if (IsOldTransactionExisted(transaction))
            {
                msg = _builder.BuildMessageTransaction(transaction, transactions[transaction.Symbol]);
            }
            else
            {
                msg = _builder.BuildMessageTransaction(transaction, transaction);
            }
            return msg;
        }

        private bool IsOldTransactionExisted(PriceLibrary.ChartService.Transaction transaction)
        {
            return _dataSource.Transactions.ContainsKey(transaction.Symbol);
        }
        #endregion

    }
}
